/******************************************************************************/
#include "stdafx.h"
#include "Main.h"
/******************************************************************************/
DataLibrary DL    ; // collection of string libraries for common exchanged file names
File        DLFile; // 'DL' data library stored as 'File'
/******************************************************************************/
void DataLibrary::save(File &f)
{
   File temp; temp.writeMem();
   skel.save(temp);
   anim.save(temp);
   mesh.save(temp);
    obj.save(temp);
   temp.pos(0); Compress(temp, f, COMPRESS_LZMA);
}
Bool DataLibrary::load(File &f)
{
   File temp; temp.writeMem();
   if(Decompress(f, temp))
   {
      temp.pos(0);
      if(!skel.load(temp))return false;
      if(!anim.load(temp))return false;
      if(!mesh.load(temp))return false;
      if(! obj.load(temp))return false;
      return true;
   }
   return false;
}
/******************************************************************************/
Traffic::Traffic()
{
   last_time=send_speed=receive_speed=0;
   last_sent=last_received=0;
}
void Traffic::update(I64 sent, I64 received)
{
   Flt d =Time.curTime()-last_time;
   if( d>=5) // 5 seconds passed since last traffic measurement, so calculate new traffic averages
   {
      last_time=Time.curTime();
      send_speed   =(sent    -last_sent    )/d; last_sent    =sent    ;
      receive_speed=(received-last_received)/d; last_received=received;
   }
}
/******************************************************************************/
Bool ValidName(Str name)
{
   return name.length()>=1 && name.length()<=32 && name.first()!=' ' && name.first()!='.' && GetBase(name)==name && CleanFileName(name)==name && !Contains(name,'@'); // '@' is used by 'SafeOverwrite' function
}
Bool ValidPassword(Str password)
{
   return password.length()>=3 && password.length()<=16;
}
/******************************************************************************/
// CS_VERSION_CHECK
/******************************************************************************/
void ClientSendVersion(Connection &conn)
{
   File f; f.writeMem().putByte(CS_VERSION_CHECK).cmpUIntV(CLIENT_SERVER_VERSION).pos(0); conn.dataFull(f, f.left());
}
Bool ServerRecvVersion(File &f)
{
   if(f.decUIntV()==CLIENT_SERVER_VERSION)return true;
   return false;
}
void ServerSendVersion(Connection &conn, Bool ok)
{
   File f; f.writeMem().putByte(CS_VERSION_CHECK).putBool(ok).pos(0); conn.dataFull(f, f.left(), false);
}
Bool ClientRecvVersion(File &f)
{
   return f.getBool();
}
/******************************************************************************/
// CS_INIT_CONN
/******************************************************************************/
void ClientSendInitConnection(Connection &conn)
{
   File f; f.writeMem().putByte(CS_INIT_CONN).putFlt(Time.curTime()); DateTime().getUTC().save(f); f.pos(0); conn.dataFull(f, f.left());
}
void ServerRecvInitConnection(File &f, Flt &time_difference, DateTime &client_utc)
{
   time_difference=f.getFlt()-Time.realTime(); // get initial time difference
   client_utc.load(f);
}
void ServerSendInitConnection(Connection &conn)
{
   File f; f.writeMem().putByte(CS_INIT_CONN);
   DateTime().getUTC().save(f);   // save Server UTC time
   DLFile.pos(0); DLFile.copy(f); // save Data Library
   f.pos(0); conn.dataFull(f, f.left(), false);
}
Bool ClientRecvInitConnection(Connection &conn, DateTime &server_utc)
{
   server_utc.load(conn.data);          // server time
   if(!DL.load(conn.data))return false; // load Data Library
   return true;
}
/******************************************************************************/
// CS_REGISTER
/******************************************************************************/
void ClientSendRegister(Connection &conn, C Str &name, C Str &password, C Str &email)
{
   File f; f.writeMem().putByte(CS_REGISTER).putStr(name).putStr(password).putStr(email).pos(0); conn.dataFull(f, f.left());
}
void ServerRecvRegister(File &f, Str &name, Str &password, Str &email)
{
   f.getStr(name    );
   f.getStr(password);
   f.getStr(email   );
}
void ServerSendRegister(Connection &conn, Bool ok)
{
   File f; f.writeMem().putByte(CS_REGISTER).putBool(ok).pos(0); conn.dataFull(f, f.left(), false);
}
void ClientRecvRegister(File &f, Bool &ok)
{
   ok=f.getBool();
}
/******************************************************************************/
// CS_LOGIN
/******************************************************************************/
void ClientSendLogin(Connection &conn, C Str &name, C Str &password)
{
   File f; f.writeMem().putByte(CS_LOGIN).putStr(name).putStr(password).pos(0); conn.dataFull(f, f.left());
}
void ServerRecvLogin(File &f, Str &name, Str &password)
{
   f.getStr(name    );
   f.getStr(password);
}
void ServerSendLogin(Connection &conn, LOGIN_RESULT result)
{
   File f; f.writeMem().putByte(CS_LOGIN).putByte(result); f.pos(0); conn.dataFull(f, f.left(), false);
}
void ClientRecvLogin(File &f, LOGIN_RESULT &result)
{
   result=LOGIN_RESULT(f.getByte());
}
/******************************************************************************/
// CS_TIME_TEST
/******************************************************************************/
void ClientSendTimeTest(Connection &conn)
{
   File f; f.writeMem().putByte(CS_TIME_TEST).putFlt(Time.curTime()).pos(0); conn.dataFull(f, f.left(), true); // send now, don't queue, as time difference is critical
}
void ServerRecvTimeTest(File &f, Flt &cur_time)
{
   cur_time=f.getFlt();
}
/******************************************************************************/
// CS_LOGOUT
/******************************************************************************/
void ClientLogout(Connection &conn)
{
   File f; f.writeMem().putByte(CS_LOGOUT).pos(0); conn.dataFull(f, f.left());
}
/******************************************************************************/
// CS_BYE
/******************************************************************************/
void ClientSendBye(Connection &conn)
{
   File f; f.writeMem().putByte(CS_BYE).pos(0); conn.dataFull(f, f.left());
}
/******************************************************************************/
// CS_DEBUG
/******************************************************************************/
void ClientSendDebug(Connection &conn, C Str &message)
{
   File f; f.writeMem().putByte(CS_DEBUG).putStr(message).pos(0); conn.dataFull(f, f.left());
}
void ServerRecvDebug(File &f, Str &message)
{
   f.getStr(message);
}
/******************************************************************************/
// CS_LIST_CHRS
/******************************************************************************/
void ClientSendListChrsRequest(Connection &conn)
{
   File f; f.writeMem().putByte(CS_LIST_CHRS).pos(0); conn.dataFull(f, f.left());
}
void ServerSendListChrs(Connection &conn, Memc<NetChr> &chrs)
{
   File f; f.writeMem().putByte(CS_LIST_CHRS);
   f.putByte(chrs.elms());
   FREPAO(chrs).compress(f);
   f.pos(0); conn.dataFull(f, f.left());
}
void ClientRecvListChrs(File &f, Memc<NetChr> &chrs)
{
   chrs.setNum(f.getByte());
   FREPAO(chrs).decompress(f);
}
/******************************************************************************/
// CS_CREATE_CHR
/******************************************************************************/
void ClientSendCreateChr(Connection &conn, ChrCreateRequest &ccr)
{
   File f; f.writeMem().putByte(CS_CREATE_CHR); ccr.compress(f); f.pos(0); conn.dataFull(f, f.left());
}
void ServerRecvCreateChr(File &f, ChrCreateRequest &ccr)
{
   ccr.decompress(f);
}
void ServerSendCreateChr(Connection &conn, CHR_CREATE_RESULT result)
{
   File f; f.writeMem().putByte(CS_CREATE_CHR).putByte(result); f.pos(0); conn.dataFull(f, f.left(), false);
}
void ClientRecvCreateChr(File &f, CHR_CREATE_RESULT &result)
{
   result=(CHR_CREATE_RESULT)f.getByte();
}
/******************************************************************************/
// CS_DELETE_CHR
/******************************************************************************/
void ClientSendDeleteChr(Connection &conn, C Str &chr_name, C Str &account_password)
{
   File f; f.writeMem().putByte(CS_DELETE_CHR).putStr(chr_name).putStr(account_password).pos(0); conn.dataFull(f, f.left());
}
void ServerRecvDeleteChr(File &f, Str &chr_name, Str &account_password)
{
   f.getStr(chr_name        );
   f.getStr(account_password);
}
/******************************************************************************/
// CS_ENTER_GAME
/******************************************************************************/
void ClientSendEnterGame(Connection &conn, C Str &chr_name)
{
   File f; f.writeMem().putByte(CS_ENTER_GAME).putStr(chr_name).pos(0); conn.dataFull(f, f.left());
}
void ServerRecvEnterGame(File &f, Str &chr_name)
{
   f.getStr(chr_name);
}
void ServerSendEnterGame(Connection &conn, Bool ok, NetChr &chr)
{
   File f; f.writeMem().putByte(CS_ENTER_GAME).putBool(ok); if(ok)chr.compress(f); f.pos(0); conn.dataFull(f, f.left(), false);
}
void ClientRecvEnterGame(File &f, Bool &ok, NetChr &chr)
{
   ok=f.getBool();
   if(ok)chr.decompress(f);
}
/******************************************************************************/
// CS_LEAVE_GAME
/******************************************************************************/
void ClientLeaveGame(Connection &conn)
{
   File f; f.writeMem().putByte(CS_LEAVE_GAME).pos(0); conn.dataFull(f, f.left());
}
/******************************************************************************/
// CS_CHR_DISCONNECT
/******************************************************************************/
void ServerSendChrDisconnect(Connection &conn, C SockAddr &addr)
{
   File f; f.writeMem().putByte(CS_CHR_DISCONNECT); addr.save(f); f.pos(0); conn.dataFull(f, f.left(), false);
}
void ClientRecvChrDisconnect(File &f, SockAddr &addr)
{
   addr.load(f);
}
/******************************************************************************/
// CS_CHR_CONNECT
/******************************************************************************/
void ServerSendChrConnect(Connection &conn, ChrInfo &ci)
{
   File f; f.writeMem().putByte(CS_CHR_CONNECT); ci.save(f); f.pos(0); conn.dataFull(f, f.left(), false);
}
void ClientRecvChrConnect(File &f, ChrInfo &ci)
{
   ci.load(f);
}
/******************************************************************************/
// CS_CHR_VISUALS
/******************************************************************************/
void ServerWriteChrVisuals(File &f, ChrVisuals &cv)
{
   f.writeMem(); cv.save(f);
}
void ServerSendChrVisuals(Connection &conn, ChrVisuals &cv)
{
   File f; f.writeMem(); cv.save(f); f.pos(0); conn.dataFull(f, f.left(), false);
}
void ClientRecvChrVisuals(File &f, ChrVisuals &cv)
{
   cv.load(f);
}
/******************************************************************************/
// CS_CHR_POS
/******************************************************************************/
void ClientSendChrPos(Connection &conn, ChrPos &cp)
{
   File f; f.writeMem(); cp.save(f, false); f.pos(0); conn.dataFull(f, f.left());
}
void ServerRecvChrPos(Connection &conn, ChrPos &cp)
{
   cp.load(conn.data, false); cp.addr=conn.address();
}
void ServerWriteChrPos(File &f, ChrPos &cp)
{
   f.writeMem(); cp.save(f, true);
}
void ServerSendChrPos(Connection &conn, ChrPos &cp)
{
   File f; f.writeMem(); cp.save(f, true); f.pos(0); conn.dataFull(f, f.left(), false);
}
void ClientRecvChrPos(File &f, ChrPos &cp)
{
   cp.load(f, true);
}
/******************************************************************************/
// CS_CHR_ANIM
/******************************************************************************/
void ClientSendChrAnim(Connection &conn, C Str &anim)
{
   File f; f.writeMem().putByte(CS_CHR_ANIM); DL.anim.putStr(f, anim); f.pos(0); conn.dataFull(f, f.left());
}
void ServerRecvChrAnim(File &f, Str &anim)
{
   DL.anim.getStr(f, anim);
}
void ServerWriteChrAnim(File &f, C SockAddr &addr, C Str &anim)
{
   f.writeMem().putByte(CS_CHR_ANIM); addr.save(f); DL.anim.putStr(f, anim);
}
void ClientRecvChrAnim(File &f, SockAddr &addr, Str &anim)
{
   addr.load(f); DL.anim.getStr(f, anim);
}
/******************************************************************************/
// CS_CHR_INV_SLOTS
/******************************************************************************/
void ClientSendChrInvSlots(Connection &conn, Int (&slots)[SLOT_NUM])
{
   File f; f.writeMem().putByte(CS_CHR_INV_SLOTS); f<<slots; f.pos(0); conn.dataFull(f, f.left());
}
void ServerRecvChrInvSlots(File &f, Int (&slots)[SLOT_NUM])
{
   f>>slots;
}
/******************************************************************************/
// CS_CHAT
/******************************************************************************/
void ClientSendChat(Connection &conn, C Str &text)
{
   File f; f.writeMem().putByte(CS_CHAT).putStr(text); f.pos(0); conn.dataFull(f, f.left());
}
void ServerRecvChat(File &f, Str &text)
{
   f.getStr(text);
}
void ServerWriteChat(File &f, C SockAddr &addr, C Str &text)
{
   f.writeMem().putByte(CS_CHAT); addr.save(f); f.putStr(text);
}
void ClientRecvChat(File &f, SockAddr &addr, Str &text)
{
   addr.load(f); f.getStr(text);
}
/******************************************************************************/
